{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<table style=\"float:left; border:none\">\n",
    "   <tr style=\"border:none; background-color: #ffffff\">\n",
    "       <td style=\"border:none\">\n",
    "           <a href=\"http://bokeh.pydata.org/\">     \n",
    "           <img \n",
    "               src=\"assets/bokeh-transparent.png\" \n",
    "               style=\"width:50px\"\n",
    "           >\n",
    "           </a>    \n",
    "       </td>\n",
    "       <td style=\"border:none\">\n",
    "           <h1>Bokeh 教程</h1>\n",
    "       </td>\n",
    "   </tr>\n",
    "</table>\n",
    "\n",
    "<div style=\"float:right;\"><h2>11. 运行 Bokeh 应用</h2></div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Bokeh的架构是这样的，高层的“模型对象”（表示plots, ranges, axes, glyphs等）使用Python创建，然后转换成JSON格式传递给客户端库BokehJS。使用Bokeh服务器，则能够保持“模型对象”在Python和浏览器间彼此同步，创造强大的能力：\n",
    "\n",
    "* 使用Python的强劲功能进行计算或查询来响应浏览器中的UI和工具事件\n",
    "* 自动推送更新浏览器中的UI（即小部件或图表）\n",
    "* 使用周期，超时，和异步回调来驱动无缝更新 \n",
    "\n",
    "***这种 Python 和 浏览器 之间的同步能力是 Bokeh server 的主要目的。***"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<center><div style=\"font-size: 18pt;color: firebrick;\"> 注意：以下作业需要在notebook之外的工作 <div></center>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "# Hello Bokeh\n",
    "\n",
    "要尝试下面的示例，将代码复制到文件 ``hello.py`` 中，然后执行：\n",
    "```bash\n",
    "bokeh serve --show hello.py \n",
    "```\n",
    "----"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "# hello.py \n",
    "\n",
    "from bokeh.io import curdoc\n",
    "from bokeh.layouts import column\n",
    "from bokeh.models.widgets import TextInput, Button, Paragraph\n",
    "\n",
    "# create some widgets\n",
    "button = Button(label=\"Say HI\")\n",
    "input = TextInput(value=\"Bokeh\")\n",
    "output = Paragraph()\n",
    "\n",
    "# add a callback to a widget\n",
    "def update():\n",
    "    output.text = \"Hello, \" + input.value\n",
    "button.on_click(update)\n",
    "\n",
    "# create a layout for everything\n",
    "layout = column(button, input, output)\n",
    "\n",
    "# add the layout to curdoc\n",
    "curdoc().add_root(layout)\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "让我们尝试一个练习：修改这个示例来添加另一个控件。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# EXERCISE: add a Select widget to this example that offers several different greetings\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 连接Plots和Widgets\n",
    "\n",
    "要尝试下面的例子，将代码复制到一个文件 ``app.py`` 中，然后执行：\n",
    "```bash\n",
    "bokeh serve --show app.py\n",
    "```\n",
    "----"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "# app.py\n",
    "\n",
    "from numpy.random import random\n",
    "\n",
    "from bokeh.io import curdoc\n",
    "from bokeh.layouts import column, row\n",
    "from bokeh.plotting import ColumnDataSource, Figure\n",
    "from bokeh.models.widgets import Select, TextInput\n",
    "\n",
    "def get_data(N):\n",
    "    return dict(x=random(size=N), y=random(size=N), r=random(size=N) * 0.03)\n",
    "\n",
    "source = ColumnDataSource(data=get_data(200))\n",
    "\n",
    "p = Figure(tools=\"\", toolbar_location=None)\n",
    "r = p.circle(x='x', y='y', radius='r', source=source,\n",
    "             color=\"navy\", alpha=0.6, line_color=\"white\")\n",
    "\n",
    "COLORS = [\"black\", \"firebrick\", \"navy\", \"olive\", \"goldenrod\"]\n",
    "select = Select(title=\"Color\", value=\"navy\", options=COLORS)\n",
    "input = TextInput(title=\"Number of points\", value=\"200\")\n",
    "\n",
    "def update_color(attrname, old, new):\n",
    "    r.glyph.fill_color = select.value\n",
    "select.on_change('value', update_color)\n",
    "\n",
    "def update_points(attrname, old, new):\n",
    "    N = int(input.value)\n",
    "    source.data = get_data(N)\n",
    "input.on_change('value', update_points)\n",
    "\n",
    "layout = column(row(select, input, width=400), row(p))\n",
    "\n",
    "curdoc().add_root(layout)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "# EXERCISE: add more widgets to change more aspects of this plot\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Streaming Data\n",
    "\n",
    "通过使用 ``stream`` 方法，可以高效地将新数据导流到列数据源。这个方法接受两个参数：\n",
    "* ``new_data`` &mdash; 与列数据源结构相同的字典\n",
    "* ``rollover`` &mdash; client上的最大列长度（较早的数据被丢弃） *[可选]*\n",
    "\n",
    "如果未指定 ``rollover``，则在client上的数据不会丢弃，而列的增长没有限制。\n",
    "\n",
    "导流数据结合周期性回调函数通常非常有用。``curdoc()`` 的 ``add_periodic_callback`` 方法接受一个回调函数，和一个时间间隔（毫秒）以重复执行此回调函数。\n",
    "\n",
    "要尝试下面的示例，请将代码复制到一个文件 ``stream.py`` 中，然后执行：\n",
    "```bash\n",
    "bokeh serve --show stream.py\n",
    "```\n",
    "----"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```python\n",
    "# stream.py\n",
    "from math import cos, sin\n",
    "\n",
    "from bokeh.io import curdoc\n",
    "from bokeh.models import ColumnDataSource\n",
    "from bokeh.plotting import figure\n",
    "\n",
    "p = figure(x_range=(-1.1, 1.1), y_range=(-1.1, 1.1))\n",
    "p.circle(x=0, y=0, radius=1, fill_color=None, line_width=2)\n",
    "\n",
    "# this is the data source we will stream to\n",
    "source = ColumnDataSource(data=dict(x=[1], y=[0]))\n",
    "p.circle(x='x', y='y', size=12, fill_color='white', source=source)\n",
    "\n",
    "def update():\n",
    "    x, y = source.data['x'][-1], source.data['y'][-1]\n",
    "  \n",
    "    # construct the new values for all columns, and pass to stream\n",
    "    new_data = dict(x=[x*cos(0.1) - y*sin(0.1)], y=[x*sin(0.1) + y*cos(0.1)])\n",
    "    source.stream(new_data, rollover=8)\n",
    "\n",
    "curdoc().add_periodic_callback(update, 150)\n",
    "curdoc().add_root(p)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "### EXERCISE: starting with the above example, create your own streaming plot\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
